package com.urbansquall.chaos{
	
import flash.utils.*;

/* Register a bunch of options that might have a weight bias
 * Then grab an option that respects the weight bias.
 * Grabbing an option will not chance the weight bias.
 * Ie: It is possible to get the same option twice in a row
 */

public class WeightedRandom
{
	private var m_random : PseudoRandom;
	private var m_options : Dictionary;
	private var m_totalWeight : Number;
	
	public function WeightedRandom( a_random : PseudoRandom = null )
	{
		if( a_random == null )
		{
			a_random = new PseudoRandom( getTimer() );
		}
		
		m_random = a_random;
		m_options = new Dictionary( false );
		
		m_totalWeight = 0.0;
	}
	
	public function dispose() : void
	{
		m_random = null;
		for( var key : String in m_options )
		{
			delete m_options[ key ];
		}
		
		m_options = null;
	}
	
	public function registerOption( a_option : Object, a_weight : Number ) : void
	{
		if( a_weight < 0 )
		{
			trace( "WeightedRandom::registerOption. Bad weight for " + a_option );
			return;
		}
		
		m_totalWeight += a_weight;
		m_options[ a_option ] = a_weight;
	}
	
	public function unregisterOption( a_option : Object ) : void
	{
		if( m_options[ a_option ] == null ) return;
		
		m_totalWeight -= m_options[ a_option ];
		
		delete m_options[ a_option ];
	}
	
	public function changeWeight( a_option : Object, a_newWeight : Number ) : void
	{
		unregisterOption( a_option );
		registerOption( a_option, a_newWeight );
	}
	
	public function grabOption() : Object
	{
		var random : Number = m_random.random();
		var target : Number = m_totalWeight * random;
		
		var accruedWeight : Number = 0;
		for( var key : Object in m_options )
		{
			var weight : Number = m_options[ key ];
			accruedWeight += weight;
			if( accruedWeight >= target )
				return key;
		}
		
		return null;
	}
	
	public function get totalWeight() : Number { return m_totalWeight; }
	
	public function toString() : String
	{
		var result : String = "[WeightedRandom ";
		for( var key : Object in m_options )
		{
			var weight : Number = m_options[ key ];
			result += "{" + key + ":" + weight + "}";
		}
		result += "]";
		
		return result;
	}
}

}